#pragma once

#include <limits>
#include "raster.h"
#include "color.h"

namespace img {

/// alpha raster virtualy combines rgb-channels from one image and alpha channel from
///	another monochrome raster
template <class I, class M> 
class alpha_raster {
	typedef typename I::elem_type I_elem_type;
public:
	typedef typename I_elem_type::component_type component_type;
	typedef BGRA<component_type> elem_type;
	typedef typename xtd::type_traits<elem_type>::real_type real_elem_type;
	typedef const_raster_iterator<alpha_raster<I, M>, elem_type> const_iterator;
public:
	I const & _rgb;
	M const & _alpha;
	bool const _inverse_alpha;
public:
	alpha_raster(I const & rgb, M const & alpha, bool inverse_alpha) 
		: _rgb(rgb), _alpha(alpha), _inverse_alpha(inverse_alpha) 
		{ assert(rgb.dim() == alpha.dim()); }
	size_type width() const 
		{ return _rgb.width(); }
	size_type height() const
		{ return _rgb.height(); }
	size_extent dim() const
		{ return _rgb.dim(); }
	bool empty() const
		{ return _rgb.empty(); }
	elem_type operator () (size_type x, size_type y) const {
		I_elem_type i = _rgb(x, y);
		component_type a = _alpha(x, y);
		if (_inverse_alpha)
			a = std::numeric_limits<component_type>::max() - a;
		return elem_type(i.b, i.g, i.r, a);
	}
	elem_type operator [] (point<size_type> p) const 
		{ return operator()(p.x, p.y); }
	elem_type operator [] (point<int> p) const
		{ return operator()(p.x, p.y); }
	real_elem_type operator () (float x, float y) const
		{ return interpolate(* this, x, y); }
	real_elem_type operator [] (point<float> p) const
		{ return interpolate(* this, p.x, p.y); }
	const_iterator begin() const
		{ return const_iterator(* this, 0, 0); }
	const_iterator end() const
		{ return const_iterator(* this, 0, _height); }
};

template <class I, class M> 
inline alpha_raster<I, M> make_alpha_raster(I const & rgb, M const & alpha, bool inverse_alpha = false)
	{ return alpha_raster<I, M>(rgb, alpha, inverse_alpha); }

/// alpha product raster resembles alpha raster, 
///	but alpha channel of the result is equal to product of original alpha channel and second monochrome raster
template <class I, class M> 
class alpha_product_raster {
	typedef typename I::elem_type I_elem_type;
public:
	typedef typename I_elem_type::component_type component_type;
	typedef BGRA<component_type> elem_type;
	typedef typename xtd::type_traits<elem_type>::real_type real_elem_type;
	typedef const_raster_iterator<alpha_product_raster<I, M>, elem_type> const_iterator;
public:
	I const & _rgb;
	M const & _alpha;
	bool const _inverse_alpha;
public:
	alpha_product_raster(I const & rgb, M const & alpha, bool inverse_alpha) 
		: _rgb(rgb), _alpha(alpha), _inverse_alpha(inverse_alpha) 
		{ assert(rgb.dim() == alpha.dim()); }
	size_type width() const 
		{ return _rgb.width(); }
	size_type height() const
		{ return _rgb.height(); }
	size_extent dim() const
		{ return _rgb.dim(); }
	bool empty() const
		{ return _rgb.empty(); }
	elem_type operator () (size_type x, size_type y) const {
		I_elem_type i = _rgb(x, y);
		component_type a = _alpha(x, y);
		if (_inverse_alpha)
			a = std::numeric_limits<component_type>::max() - a;
		return elem_type(i.b, i.g, i.r, i.a * a / std::numeric_limits<component_type>::max());
	}
	elem_type operator [] (point<size_type> p) const 
		{ return operator()(p.x, p.y); }
	elem_type operator [] (point<int> p) const
		{ return operator()(p.x, p.y); }
	real_elem_type operator () (float x, float y) const
		{ return interpolate(* this, x, y); }
	real_elem_type operator [] (point<float> p) const
		{ return interpolate(* this, p.x, p.y); }
	const_iterator begin() const
		{ return const_iterator(* this, 0, 0); }
	const_iterator end() const
		{ return const_iterator(* this, 0, height()); }
};

template <class I, class M> 
inline alpha_product_raster<I, M> make_alpha_product_raster(I const & rgb, M const & alpha, bool inverse_alpha = false) 
	{ return alpha_product_raster<I, M>(rgb, alpha, inverse_alpha); }

} //namespace img
